#include "kernel/timer/time.h"
#include "kernel/log/log.h"
#include "kernel/memory/memory.h"
#include "kernel/interrupt/interrupt.h"
#include "kernel/apic/apic.h"
#include "libs/msr.h"
#include "kernel/task/task.h"
#include "kernel/apic/ipi.h"
#include "kernel/smp/smp.h"
#include "kernel/timer/pit.h"

#define IO_TIMER1       0x040           // 8253 Timer #1
#define TIMER_FREQ      1193182
#define	TIMER_CNTR      (IO_TIMER1 + 0)	// timer counter port
#define TIMER_MODE      (IO_TIMER1 + 3) // timer mode port
#define TIMER_SEL0      0x00    // select counter 0
#define TIMER_TCOUNT    0x00    // mode 0, terminal count
#define TIMER_16BIT     0x30    // r/w counter 16 bits, LSB first
#define TIMER_STAT      0xe0    // read status mode
#define TIMER_STAT0     (TIMER_STAT | 0x2)  // status mode counter 0



TimerTask::TimerTask(uint64_t expire_time/* args */)
{

    internalTime =  expire_time;
    this->expire_time = TIMEMANAGER->timeCount + internalTime;
    
}

TimerTask::~TimerTask()
{




}

void TimerTask::handler(){

    LOG_INFO("internal timer:%d\n",expire_time);

    this->expire_time = TIMEMANAGER->timeCount + internalTime;
    TIMEMANAGER->taskQueue.push(this);

 }







HpetTimer::HpetTimer()
{
    uint32_t x;
    uint32_t * p;

	// getHpetACPITable();
	// 1010 0010 0000 0001
	hpetRegsAddr = (unsigned char *)Phy_To_Virt(0xfed00000);

	// uint64_t value = *(uint64_t*)(hpetRegsAddr);
	// LOG_INFO("value:%lx\n",value);

	*(uint64_t*)(hpetRegsAddr +0x10) = 0x0;
	io_mfence();	

    //edge triggered & periodic
   *(uint64_t*)(hpetRegsAddr +0x100) = 0x0044;
    io_mfence();


    //1S
    // *(uint64_t*)(hpetRegsAddr +0x108) = 0x10;
    // io_mfence();


	*(uint64_t*)(hpetRegsAddr +0xF0) = 0;
	io_mfence();


    
    // //init MAIN_CNT & get CMOS time
	time tmptime;
    TIMEMANAGER->getCMOSRTC(&tmptime);

    TIMEMANAGER->logTime();

}

HpetTimer::~HpetTimer()
{

}









ApicTimer::ApicTimer(uint64_t number)
{

    x2apichz = 0;
    
	#define MSR_IA32_X2APIC_LVT_TIMER     0x832
	#define APIC_LVT_TIMER_ONESHOT        0x00
	#define APIC_LVT_TIMER_PERIODIC       0x20000
	#define APIC_LVT_TIMER_TSCDEADLINE    0x40000
	#define APIC_LVT_TIMER_MASKED         0x10000
	

    wrmsr(IA32_APIC_TIMER_FREQUENCE,0X0000000b);
    wrmsr(IA32_APIC_TIMER_COUNTER,0xffffffff);
    uint64_t ccr0 = rdmsr(IA32_APIC_TIMER_CURRENT_COUNTER);
    delayMicro(10 * 1000);  // 1 / 100 of one second
    uint64_t ccr1 = rdmsr(IA32_APIC_TIMER_CURRENT_COUNTER);
    x2apichz = 100 *  (ccr0 - ccr1);
    uint64_t periodicTime = (TIMEMANAGER->Quantun * x2apichz) / 1000;
    if(periodicTime > 0xffffffff)
        LOG_ERROR("init x2apic:QUANTUM too large!\n");

    wrmsr(IA32_APIC_TIMER_FREQUENCE,0x0000000b);
    wrmsr(IA32_APIC_TIMER,APIC_LVT_TIMER_PERIODIC | IRQ_LOCALAPIC_BASE + IRQ_LOCALAPIC_TIMER);
    wrmsr(IA32_APIC_TIMER_COUNTER,periodicTime);

    wrmsr(IA32_APIC_ERROR_STATUS,0);
    wrmsr(IA32_APIC_ERROR_STATUS,0);

    wrmsr(IA32_APIC_EOI,0x0);


    // //init MAIN_CNT & get CMOS time
	time tmptime;
    TIMEMANAGER->getCMOSRTC(&tmptime);
	
    // APIC_LVT  entry;
	// entry.vector = 0x20;
	// entry.deliver_status = APIC_ICR_IOAPIC_Idle;
	// entry.mask = APIC_ICR_IOAPIC_UN_Masked;
	// entry.timer_mode = APIC_LVT_Timer_One_Shot;

	// entry.deliver_mode = 0 ;
	// entry.polarity = 0;
	// entry.irr = 0;
	// entry.trigger = 0;
	// entry.res_1 = 0;
	// entry.res_2 = 0;
	// wrmsr(IA32_APIC_TIMER,*(uint32_t*)&entry);
	// wrmsr(IA32_APIC_TIMER_COUNTER,0x10000);
	// wrmsr(IA32_APIC_TIMER_FREQUENCE,0x3);
	
//     // Disable the timer
//     uint64_t val = rdmsr(MSR_IA32_X2APIC_LVT_TIMER);
//     val |= APIC_LVT_TIMER_MASKED;
//     wrmsr(MSR_IA32_X2APIC_LVT_TIMER, val);

//     // Set the interrupt type
//     val = rdmsr(MSR_IA32_X2APIC_LVT_TIMER);
//     val &= ~0x700;  // Clear bits 10:8
//     val |= APIC_LVT_TIMER_PERIODIC;  // Set to periodic interrupt mode
//     wrmsr(MSR_IA32_X2APIC_LVT_TIMER, val);
//  // Set the interrupt vector
//     val = rdmsr(MSR_IA32_X2APIC_LVT_TIMER);
//     val &= ~0xFF00;  // Clear bits 15:8
//     val |= 0x20;  // Set interrupt vector to 0xF0 (240 in decimal)
//     wrmsr(MSR_IA32_X2APIC_LVT_TIMER, val);

//     // Set the timer initial count
//     val = rdmsr(IA32_APIC_TIMER_COUNTER);
//     val &= 0xFFFFFFFF00000000ull;  // Clear bits 63:32
//     val |= 0xFFFFFFFF;  // Set bits 31:0 to the initial count value
//     wrmsr(IA32_APIC_TIMER_COUNTER, val);

//     // Set the timer divide configuration
//     val = rdmsr(IA32_APIC_TIMER_FREQUENCE);
//     val &= ~0xC000000;  // Clear bits 29:28
//     val |= 0x1;  // Set bits 28 to divide by 2
//     wrmsr(IA32_APIC_TIMER_FREQUENCE, val);

//     // Enable the timer
//     val = rdmsr(MSR_IA32_X2APIC_LVT_TIMER);
//     val &= ~APIC_LVT_TIMER_MASKED;
//     wrmsr(MSR_IA32_X2APIC_LVT_TIMER, val);
	

}

ApicTimer::~ApicTimer(){



}



TimeManager* TimeManager::timem;
TimeManager::TimeManager(/* args */)
:interrupthandler(32,INTERRUPTMANAGER)
,SoftInterruptHandler(SOFTIRQ_TIME)
{

    timem = this;
    initHz();
    timeCount = 0;
    TIMEMANAGER->Quantun = 20000;
    
    // IO_APIC_RET_entry entry;
   
	// entry.vector = 34;
	// entry.deliver_mode = APIC_ICR_IOAPIC_Fixed ;
	// entry.dest_mode = ICR_IOAPIC_DELV_PHYSICAL;
	// entry.deliver_status = APIC_ICR_IOAPIC_Idle;
	// entry.polarity = APIC_IOAPIC_POLARITY_HIGH;
	// entry.irr = APIC_IOAPIC_IRR_RESET;
	// entry.trigger = APIC_ICR_IOAPIC_Edge;
	// entry.mask = APIC_ICR_IOAPIC_Masked;
	// entry.reserved = 0;

	// entry.destination.physical.reserved1 = 0;
	// entry.destination.physical.phy_dest = 0;
	// entry.destination.physical.reserved2 = 0;

	// install(&entry);
	// enable();

    // hpet = new HpetTimer();
    apict = new ApicTimer(0x20);


    
}

TimeManager::~TimeManager()
{
    disable();
    uninstall();
}

StackFrame* TimeManager::handleInterrupt(StackFrame* fs){
   

    timeCount++;
    uint64_t cpuid = getAPICID();
    
    // IPIMANAGER->sendIpi(0x1,IPIHPET_VECTOR);


    if(TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies <= 0){

        current->flags |=NEED_SCHEDULE;

    }

    if(INTERRUPTMANAGER->taskManagerHaveFinish){
    
        
        switch(current->priority){

        case 0:
        case 1:
            TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies--;
                current->vrunTime += 1;
                break;
        case 2:
        default:
            TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies-=2;
                current->vrunTime += 2;
                break;
        }
        


    }

    // IPIMANAGER->sendIpi(0x1,IPISCHEDULE_VECTOR);


    if((!taskQueue.isEmpty() && taskQueue.get()->expire_time <= timeCount))
        SOFTINTERRUPTMANAGER->setSoftIrqStatus(SOFTIRQ_TIME_FLAG);


}


void TimeManager::handleSoftInterrupt(){

    
    if(!taskQueue.isEmpty()){
        do
        {
            TimerTask* temp = taskQueue.get();
            if(temp->expire_time > timeCount)
                break;
            temp->handler();
            delTimerTask(temp);
        } while (!taskQueue.isEmpty());
    
    }
 
    
    
    
}


int TimeManager::getCMOSRTC(time* time){


    do{

        time->year = CMOS_READ(0x09) + CMOS_READ(0x32) * 0x100;
        time->month = CMOS_READ(0x08);
        time->day = CMOS_READ(0x07);
        time->hour = CMOS_READ(0x04);
        time->minute = CMOS_READ(0x02);
		time->second = CMOS_READ(0x00);

    }while(time->second != CMOS_READ(0x00));

    io_out8(PORT_RTC_INDEX,0x00);
    lastTime = *time;

}

void TimeManager::logTime(){


	// LOG_INFO("year:%#010x,month:%#010x,day:%#010x,hour:%#010x,mintue:%#010x,second:%#010x\n",lastTime.year,lastTime.month,lastTime.day,lastTime.hour,lastTime.minute,lastTime.second);

}



int TimeManager::isOneSecond(){

    cli();
    struct time time;
    int ret = 0;
    do{

        time.year = CMOS_READ(0x09) + CMOS_READ(0x32) * 0x100;
        time.month = CMOS_READ(0x08);
        time.day = CMOS_READ(0x07);
        time.hour = CMOS_READ(0x04);
        time.minute = CMOS_READ(0x02);
		time.second = CMOS_READ(0x00);

    }while(time.second != CMOS_READ(0x00));
    io_out8(PORT_RTC_INDEX,0x00);
    ret = ISONESECOND;
    
    if(ret)
        lastTime = time;
    sti();
    return ret;
}

int compareTo(TimerTask* node,TimerTask* task){
    
    return node->expire_time < task->expire_time;
}

void TimeManager::addTimerTask(TimerTask* task){

    taskQueue.push(task,compareTo);


}
void TimeManager::delTimerTask(TimerTask* task){

    taskQueue.del(task);

}







extern "C" void delayMicro(uint64_t delay){

    uint64_t tscDelay = (TIMEMANAGER->cpuhz * delay) / 1000000;

    uint64_t s = rdtsc();
    while (rdtsc() - s < tscDelay)
    {
        nop();
    }
    


}



void TimeManager::initHz()
{

    uint64_t xticks = 0x000000000000FFFFULL;
    io_out8(TIMER_MODE,TIMER_SEL0 | TIMER_TCOUNT | TIMER_16BIT);
    io_out8(IO_TIMER1,xticks % 256);
    io_out8(IO_TIMER1,xticks / 256);


    uint64_t s =  rdtsc();
    do{
        io_out8(TIMER_MODE, TIMER_STAT0);
        if(rdtsc() - s > 1ULL << 32)
        {
            cpuhz = 2 * 1000 * 1000 * 1000;
            return;
        }

    }while(!(io_in8(TIMER_CNTR) & 0x80));

    uint64_t e = rdtsc();
    
    cpuhz = ((e - s) * 10000000) / ((xticks * 10000000) / TIMER_FREQ);
    
};


